package com.gitee.deeround.jdbchelper.resultSetExtractors;

import com.gitee.deeround.jdbchelper.exception.DbException;
import com.gitee.deeround.jdbchelper.out.DataType;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.ResultSet;
import java.sql.Types;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class BaseResultSetExtractor {
    /**
     * 字段名转成小写
     */
    protected String resolveColumnName(String columnName) {
        return columnName.toLowerCase();
    }

    /**
     * 字段数据类型转自定义数据类型
     */
    protected DataType resolveDataType(int dataType) {
        //java.sql.Types
        Map<Integer, DataType> typeMap = new HashMap<>();
        typeMap.put(Types.BIT, DataType.Integer);
        typeMap.put(Types.TINYINT, DataType.Integer);
        typeMap.put(Types.SMALLINT, DataType.Integer);
        typeMap.put(Types.INTEGER, DataType.Integer);
        typeMap.put(Types.BIGINT, DataType.Integer);

        typeMap.put(Types.FLOAT, DataType.Decimal);
        typeMap.put(Types.REAL, DataType.Decimal);
        typeMap.put(Types.DOUBLE, DataType.Decimal);
        typeMap.put(Types.NUMERIC, DataType.Decimal);
        typeMap.put(Types.DECIMAL, DataType.Decimal);

        typeMap.put(Types.CHAR, DataType.String);
        typeMap.put(Types.VARCHAR, DataType.String);
        typeMap.put(Types.LONGVARCHAR, DataType.String);

        typeMap.put(Types.DATE, DataType.Date);
        typeMap.put(Types.TIME, DataType.Date);
        typeMap.put(Types.TIMESTAMP, DataType.Date);
        typeMap.put(Types.BINARY, DataType.Integer);
        typeMap.put(Types.VARBINARY, DataType.String);
        typeMap.put(Types.LONGVARBINARY, DataType.String);

        typeMap.put(Types.JAVA_OBJECT, DataType.Object);

        typeMap.put(Types.BLOB, DataType.Blob);
        typeMap.put(Types.CLOB, DataType.Clob);
        typeMap.put(Types.NCLOB, DataType.Clob);

        typeMap.put(Types.NCHAR, DataType.String);
        typeMap.put(Types.NVARCHAR, DataType.String);
        typeMap.put(Types.LONGNVARCHAR, DataType.String);
        typeMap.put(Types.TIME_WITH_TIMEZONE, DataType.Date);
        typeMap.put(Types.TIMESTAMP_WITH_TIMEZONE, DataType.Date);

        if (typeMap.containsKey(dataType)) {
            return typeMap.get(dataType);
        } else {
            throw new DbException("不支持的数据类型：" + dataType);
        }
    }


    protected Object getColumnValue(ResultSet rs, int i, String columnName, DataType dataType) {
        try {
            if (DataType.Clob.equals(dataType)) {
                Clob clob = rs.getClob(i);
                if (clob == null) {
                    return null;
                }
                // 读取 CLOB 数据（这里以读取为字符串为例）
                Reader reader = clob.getCharacterStream();
                StringBuilder sb = new StringBuilder();
                char[] buffer = new char[1024];
                int len;
                while ((len = reader.read(buffer)) != -1) {
                    sb.append(buffer, 0, len);
                }
                reader.close();
                return sb.toString();
            } else if (DataType.Blob.equals(dataType)) {
                Blob blob = rs.getBlob(i);
                if (blob == null) {
                    return null;
                }
                try (InputStream inputStream = blob.getBinaryStream()) {
                    return convert(inputStream);
                }
            }

            return rs.getObject(i);
        } catch (Exception e) {
            throw new RuntimeException("读取字段[" + columnName + "]异常：" + e.getMessage(), e);
        }
    }

    private String convert(InputStream inputStream) throws IOException {
        try (InputStream in = inputStream;
             ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {

            byte[] buffer = new byte[1024];
            int bytesRead;

            // Read data from the input stream and write it to the byte array output stream
            while ((bytesRead = in.read(buffer)) != -1) {
                byteArrayOutputStream.write(buffer, 0, bytesRead);
            }

            // Convert the byte array to a Base64 encoded string
            byte[] byteArray = byteArrayOutputStream.toByteArray();
            return Base64.getEncoder().encodeToString(byteArray);
        }
    }
}
